#pragma once
#include <windows.h>
#include <shlobj.h>
#include <objbase.h>
#include <string.h>
#include <filesystem>
#include "String/Converter.hpp"

namespace CppWinApi::Windows::WinSystem
{
    struct Shortcut
    {
        Shortcut()
        {
            sourcePath = nullptr;
            shortcutPath = nullptr;
            workDirectory = nullptr;
            iconPath = nullptr;
            description = nullptr;
        }

        char* sourcePath;
        char* shortcutPath;
        char* workDirectory;
        char* iconPath;
        char* description;
    };
    namespace fs = std::filesystem;

    static bool TryGetStartupPath(fs::path& path)
    {
        PWSTR startupPath = nullptr;
        HRESULT result = ::SHGetKnownFolderPath(
            FOLDERID_Startup, // 启动文件夹的 KNOWNFOLDERID
            0,                // 无特殊标志
            NULL,             // 当前用户
            &startupPath      // 输出路径指针
        );

        if (!SUCCEEDED(result))
        {
            return false;
        }

        path = fs::path(CppWinApi::String::Converter::WStringToGBK(startupPath));

        ::CoTaskMemFree(startupPath);
        return true;
    }

    static bool CreateShortcut(Shortcut& shortcut)
    {
        IShellLinkA* pShellLink = nullptr;
        IPersistFile* pPersistFile = nullptr;

        // 如果文件不存在
        if (shortcut.sourcePath == nullptr || ::strlen(shortcut.sourcePath) == 0 || !std::filesystem::exists(shortcut.sourcePath))
        {
            return false;
        }

        // 如果快捷方式已经存在
        if (shortcut.shortcutPath == nullptr || ::strlen(shortcut.shortcutPath) == 0 || std::filesystem::exists(shortcut.shortcutPath))
        {
            return false;
        }

        // 如果工作目录不存在
        if (shortcut.workDirectory == nullptr || ::strlen(shortcut.workDirectory) == 0 || !std::filesystem::exists(shortcut.workDirectory))
        {
            return false;
        }

        // 初始化 COM
        CoInitialize(NULL);

        // 创建 IShellLinkA 实例（ANSI 版本）
        HRESULT hr = CoCreateInstance(
            CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
            IID_IShellLinkA, (LPVOID*)&pShellLink);

        if (!SUCCEEDED(hr))
        {
            CoUninitialize();
            return false;
        }

        pShellLink->SetPath(shortcut.sourcePath);                // 设置快捷方式属性
        pShellLink->SetWorkingDirectory(shortcut.workDirectory); // 工作目录

        // 设置描述
        if (shortcut.description != nullptr && ::strlen(shortcut.description) > 0)
        {
            pShellLink->SetDescription(shortcut.description);
        }

        // 如果图标文件存在，则设置图标
        if (shortcut.iconPath != nullptr && ::strlen(shortcut.iconPath) > 0 && std::filesystem::exists(shortcut.iconPath))
        {
            pShellLink->SetIconLocation(shortcut.iconPath, 0);
        }

        // 获取 IPersistFile 接口并保存
        hr = pShellLink->QueryInterface(IID_IPersistFile, (void**)&pPersistFile);
        if (SUCCEEDED(hr))
        {
            // 将 ANSI 路径转换为宽字符（IPersistFile::Save 需要宽字符）
            WCHAR wszShortcutPath[MAX_PATH];
            MultiByteToWideChar(CP_ACP, 0, shortcut.shortcutPath, -1, wszShortcutPath, MAX_PATH);
            pPersistFile->Save(wszShortcutPath, TRUE);
            pPersistFile->Release();
        }
        pShellLink->Release();

        CoUninitialize();

        return true;
    }

    HANDLE OpenOrCreateSemaphore(const std::string& name, int initial_count, int max_count)
    {
        // 参数验证
        if (initial_count < 0 || max_count <= 0 || initial_count > max_count)
        {
            throw std::runtime_error("Invalid semaphore count parameters");
        }

        // 1. 先尝试打开已有信号量
        HANDLE hSem = OpenSemaphoreA(
            SEMAPHORE_ALL_ACCESS,
            FALSE,
            name.c_str());

        // 2. 如果打开失败且错误是对象不存在，则尝试创建
        if (hSem == nullptr && GetLastError() == ERROR_FILE_NOT_FOUND)
        {
            // 初始化安全描述符
            SECURITY_DESCRIPTOR sd;
            if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
            {
                throw std::runtime_error(
                    "InitializeSecurityDescriptor failed. Error code: " +
                    std::to_string(GetLastError()));
            }

            if (!SetSecurityDescriptorDacl(&sd, TRUE, nullptr, FALSE))
            {
                throw std::runtime_error(
                    "SetSecurityDescriptorDacl failed. Error code: " +
                    std::to_string(GetLastError()));
            }

            SECURITY_ATTRIBUTES sa = {
                sizeof(SECURITY_ATTRIBUTES),
                &sd,
                FALSE };

            // 创建新信号量
            hSem = CreateSemaphoreA(
                &sa,
                initial_count,
                max_count,
                name.empty() ? nullptr : name.c_str());

            // 3. 检查创建结果
            if (hSem == nullptr)
            {
                throw std::runtime_error(
                    "Failed to create semaphore. Error code: " +
                    std::to_string(GetLastError()));
            }
        }
        else if (hSem == nullptr)
        {
            // 打开失败但不是因为对象不存在
            throw std::runtime_error(
                "Failed to open semaphore. Error code: " +
                std::to_string(GetLastError()));
        }

        return hSem;
    }

    HANDLE OpenOrCreateMutex(const std::string& name, bool initial_owner = false)
    {
        // 1. 先尝试打开已有互斥量
        HANDLE hMutex = OpenMutexA(
            MUTEX_ALL_ACCESS,
            FALSE,
            name.c_str());

        // 2. 如果打开失败且错误是对象不存在，则尝试创建
        if (hMutex == nullptr && GetLastError() == ERROR_FILE_NOT_FOUND)
        {
            // 设置安全属性（允许所有用户访问）
            SECURITY_DESCRIPTOR sd;
            if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
            {
                throw std::runtime_error(
                    "InitializeSecurityDescriptor failed. Error code: " +
                    std::to_string(GetLastError()));
            }

            if (!SetSecurityDescriptorDacl(&sd, TRUE, nullptr, FALSE))
            {
                throw std::runtime_error(
                    "SetSecurityDescriptorDacl failed. Error code: " +
                    std::to_string(GetLastError()));
            }

            SECURITY_ATTRIBUTES sa = {
                sizeof(SECURITY_ATTRIBUTES),
                &sd,
                FALSE };

            // 创建新互斥量
            hMutex = CreateMutexA(
                &sa,
                initial_owner,
                name.empty() ? nullptr : name.c_str());

            // 3. 检查创建结果
            if (hMutex == nullptr)
            {
                throw std::runtime_error(
                    "Failed to create mutex. Error code: " +
                    std::to_string(GetLastError()));
            }
        }
        else if (hMutex == nullptr)
        {
            // 打开失败但不是因为对象不存在
            throw std::runtime_error(
                "Failed to open mutex. Error code: " +
                std::to_string(GetLastError()));
        }

        return hMutex;
    }

    HANDLE OpenOrCreateEvent(const std::string& eventName, bool manualReset = false, bool initialState = false)
    {
        // 首先尝试打开已存在的事件对象
        HANDLE hEvent = OpenEventA(EVENT_ALL_ACCESS, FALSE, eventName.c_str());

        if (hEvent == nullptr)
        {
            // 检查错误是否为对象不存在
            DWORD error = GetLastError();
            if (error != ERROR_FILE_NOT_FOUND)
            {
                throw std::runtime_error(
                    "Failed to open event object. Error code: " +
                    std::to_string(error));
            }

            // 创建新的事件对象
            hEvent = CreateEventA(
                nullptr,          // 默认安全属性
                manualReset,      // 手动重置还是自动重置
                initialState,     // 初始状态
                eventName.c_str() // 事件名称
            );

            if (hEvent == nullptr)
            {
                throw std::runtime_error(
                    "Failed to create event object. Error code: " +
                    std::to_string(GetLastError()));
            }
        }

        return hEvent;
    }
}